import { ITimer } from "../../api/timer/ITimer";
import { TimerUtils } from "../../api/timer/TimerUtils";
import { E_ActivityTimeType } from "../defs/activity/E_ActivityTimeType";
import { E_TimeConfig } from "../defs/com/E_TimeConfig";
import { CDActivity } from "../excel/CDActivity";
import { Player } from "../struct/Player";
import { SDServer } from "./SDServer";

/**活动默认持续时间 */
const DEFAULT_LAST_MINUTE = 30;
/**永远有效标记 */
const ACTIVITY_FOREVER_TIME = 1;


/**活动状态 */
export class SDActivityStatus {
    /**可能开启 */
    public exist: boolean;
    /**开始时间（< 0-永远不可能，=0-永远开启，>0-开始时间 */
    public startTime: number;
    /**结束时间 */
    public endTime: number;


    private constructor() {

    }


    /**释放 */
    public destroy(): void {
        if (SDActivityStatus.POOL.indexOf(this) === -1) {
            SDActivityStatus.POOL.push(this);
        }
    }


    /**重新使用 */
    public reuse(): void {
        this.exist = false;
        this.startTime = 0;
        this.endTime = 0;
    }


    /**缓存池 */
    private static readonly POOL: SDActivityStatus[] = [];

    /**创建 */
    public static createNew(): SDActivityStatus {
        const sas = this.POOL.pop() || (new SDActivityStatus());
        sas.reuse();
        return sas;
    }
}


/**
 * 数据-活动    
 */
export abstract class SDActivity {



    /**
     * 获取更新倒计时
     * @param player 
     * @param nowTime 
     */
    public static getUpdateCountDown(
        player: Player,
        nowTime = ITimer.getServerTime()
    ): number {

        const list = player.activity.getStatusUpdateTimeValues();
        let delay: number = E_TimeConfig.Day;

        for (let i = 0, len = list.length; i < len; i++) {
            if (ACTIVITY_FOREVER_TIME === list[i]) {
                continue;
            }
            const d = list[i] - nowTime;
            if (d < delay) {
                delay = d;
            }
        }

        if (delay === 0) {
            delay = 2;
        }

        return delay;
    }


    /**
     * 活动是否开启
     * @param player 
     * @param activityId 
     */
    public static isOpen(
        player: Player,
        activityId: number
    ): boolean {
        const v = player.activity.getOpen(activityId);
        return v === 1;
    }


    /**
     * 获取开始倒计时
     * @param player 
     * @param activityID 
     * @param nowTime 
     * @returns 0-开启中，< 0 - 不会再开启， >0-距离的毫秒数
     */
    public static getActivityCountDown(
        player: Player,
        activityID: number,
        nowTime = ITimer.getServerTime()
    ): number {

        const config = CDActivity.getData(activityID);
        if (!config) {
            return -1;
        }

        if (config.eternal !== 0) {
            return 0;
        }

        const status = this.getOpenStatus(player, activityID, nowTime);
        let r = -1;

        if (status.exist) {
            if (0 === status.startTime || nowTime >= status.startTime) {
                r = 0;
            }
            else {
                r = status.startTime - nowTime;
            }
        }

        status.destroy();

        return r;
    }


    /**
     * 获取开始倒计时
     * @param player 可能为空
     * @param activityId 
     * @param nowTime 
     * @param status
     * @returns 开启状态
     */
    public static getOpenStatus(
        player: Player,
        activityId: number,
        nowTime = ITimer.getServerTime(),
        status = SDActivityStatus.createNew(),
        serverCreateTime = 0
    ): SDActivityStatus {

        status.reuse();

        const config = CDActivity.getData(activityId);
        if (!config) {

        }
        else if (config.eternal !== 0) {
            status.exist = true;
        }
        else {
            switch (config.timeType) {
                case E_ActivityTimeType.ServerOpenTime:
                    {
                        const serverCt = serverCreateTime || SDServer.getServerCreateTime(player);
                        const serverZero = TimerUtils.getDayZeroTime(serverCt);
                        const last = (config.lastTime[0] || DEFAULT_LAST_MINUTE) * E_TimeConfig.Minute;
                        const startTime = serverZero + (config.startDay[0] || 0) * E_TimeConfig.Day;
                        const endTime = startTime + last;

                        if (nowTime <= endTime) {
                            status.exist = true;
                            status.startTime = startTime;
                            status.endTime = endTime;
                        }
                        else if (config.roundDay > 0) {
                            //周期性
                            const roundTime = config.roundDay * E_TimeConfig.Day;
                            const duration = roundTime - (nowTime - startTime) % roundTime;
                            status.exist = true;

                            const nearTime = nowTime + duration - roundTime;
                            if (nowTime >= nearTime && nowTime <= nearTime + last) {   
                                status.startTime = nearTime;   //当前在新周期中
                            }
                            else {
                                status.startTime = nowTime + duration;
                            }
                            status.endTime = status.startTime + last;
                        }
                    }
                    break;

                case E_ActivityTimeType.ActionTime:
                    {
                        let startTime = this.getSpecialTime(config.startDay);
                        const endTime = this.getSpecialTime(config.lastTime);
                        if (nowTime > endTime) {
                            break;
                        }

                        const exceptTime = config.exceptDay * E_TimeConfig.Day;
                        if (exceptTime > 0) {
                            const serverCt = serverCreateTime || SDServer.getServerCreateTime(player);
                            const serverZero = TimerUtils.getDayZeroTime(serverCt);
                            const exceptEndTime = serverZero + exceptTime;
                            if (exceptEndTime >= endTime) {
                                break;
                            }
                            if (startTime < exceptEndTime) {
                                startTime = exceptEndTime;
                            }
                        }

                        status.exist = true;
                        status.startTime = startTime;
                        status.endTime = endTime;
                    }
                    break;


                case E_ActivityTimeType.PlayerCreateTime:
                    if (player) {
                        const createZero = TimerUtils.getDayZeroTime(player.playerInfo.createTime);
                        const last = (config.lastTime[0] || DEFAULT_LAST_MINUTE) * E_TimeConfig.Minute;
                        const startTime = createZero + (config.startDay[0] || 0) * E_TimeConfig.Day;
                        const endTime = startTime + last;
                        if (nowTime > endTime) {
                            break;
                        }
                        status.exist = true;
                        status.startTime = startTime;
                        status.endTime = endTime;
                    }
                    else {
                        console.warn('get activity status with player === null');
                    }
                    break;

                case E_ActivityTimeType.SpecifyConditions:
                    if (player) {
                        const startTime = player.activity.getConditionTrigger(config.id);
                        if (startTime > 0) {
                            const last = (config.lastTime[0] || DEFAULT_LAST_MINUTE) * E_TimeConfig.Minute;
                            const endTime = startTime + last;
                            if (nowTime <= endTime) {
                                status.exist = true;
                                status.startTime = startTime;
                                status.endTime = endTime;
                            }
                        }
                    }
                    else {
                        console.warn('get activity status with player === null');
                    }
                    break;

                case E_ActivityTimeType.SpecialTime:
                    {
                        const zero = TimerUtils.getDayZeroTime(nowTime);
                        const last = (config.lastTime[0] || DEFAULT_LAST_MINUTE) * E_TimeConfig.Minute;
                        const weekDay = TimerUtils.getWeekDay(nowTime);
                        const weekIdx = (weekDay - 1 + 7) % 7;      //js date 0是星期天；配置那边，0是星期1

                        for (let i = 0; i < 7; i++) {
                            if (config.startDay[(i + weekIdx) % 7]) {
                                const startTime = zero + i * E_TimeConfig.Day;
                                const endTime = startTime + last;
                                if (nowTime <= endTime) {
                                    status.exist = true;
                                    status.startTime = startTime;
                                    status.endTime = endTime;
                                    break;
                                }
                            }
                        }
                    }
                    break;

                default:
                    console.warn('activity 未知的开放时间类型：' + config.timeType);
                    break;
            }
        }

        return status;
    }


    /**
     * 获取活动上一次开启时间
     * @param player 
     * @param activityId 
     * @param nowTime 
     * @param serverCreateTime 
     * @returns < 0-没有上一期，>=0 -上一期时间
     */
    public static getLastOpenTime(
        player: Player,
        activityId: number,
        nowTime: number,
        serverCreateTime = 0
    ): number {

        const config = CDActivity.getData(activityId);
        if (!config || config.eternal !== 0) {
            return -1;
        }

        switch (config.timeType) {
            case E_ActivityTimeType.ServerOpenTime:
                {
                    const serverCt = serverCreateTime || SDServer.getServerCreateTime(player);
                    const serverZero = TimerUtils.getDayZeroTime(serverCt);
                    const last = (config.lastTime[0] || DEFAULT_LAST_MINUTE) * E_TimeConfig.Minute;
                    const startTime = serverZero + (config.startDay[0] || 0) * E_TimeConfig.Day;
                    const endTime = startTime + last;

                    if (nowTime <= endTime) {
                        return -1;          //第一期还没结束
                    }

                    if (config.roundDay === 0) {
                        return startTime;   //没有循环，只有第一期
                    }

                    //周期性
                    const roundTime = config.roundDay * E_TimeConfig.Day;
                    const duration = roundTime - (nowTime - startTime) % roundTime;
                    const lt = nowTime + duration - roundTime;
                    if (lt >= 0) {
                        return lt;
                    }
                }
                break;

            case E_ActivityTimeType.ActionTime:
                {
                    const startTime = this.getSpecialTime(config.startDay);
                    const endTime = this.getSpecialTime(config.lastTime);
                    if (nowTime < endTime) {
                        return -1;      //还没开启过
                    }

                    const exceptTime = config.exceptDay * E_TimeConfig.Day;
                    if (exceptTime === 0) {
                        return -1;      //没有停止过
                    }

                    const serverCt = serverCreateTime || SDServer.getServerCreateTime(player);
                    const serverZero = TimerUtils.getDayZeroTime(serverCt);
                    const exceptEndTime = serverZero + exceptTime;
                    if (exceptEndTime < endTime) {
                        return exceptEndTime;
                    }
                }
                break;


            case E_ActivityTimeType.PlayerCreateTime:
                if (player) {
                    const createZero = TimerUtils.getDayZeroTime(player.playerInfo.createTime);
                    const last = (config.lastTime[0] || DEFAULT_LAST_MINUTE) * E_TimeConfig.Minute;
                    const startTime = createZero + (config.startDay[0] || 0) * E_TimeConfig.Day;
                    const endTime = startTime + last;
                    if (nowTime > endTime) {
                        return startTime;
                    }
                }
                else {
                    console.warn('get activity last open times with player === null');
                }
                break;

            case E_ActivityTimeType.SpecifyConditions:
                if (player) {
                    const startTime = player.activity.getConditionTrigger(config.id);
                    if (startTime > 0) {
                        const last = (config.lastTime[0] || DEFAULT_LAST_MINUTE) * E_TimeConfig.Minute;
                        const endTime = startTime + last;
                        if (nowTime > endTime) {
                            return startTime;
                        }
                    }
                }
                else {
                    console.warn('get activity last open times with player === null');
                }
                break;

            case E_ActivityTimeType.SpecialTime:
                {
                    const zero = TimerUtils.getDayZeroTime(nowTime);
                    const last = (config.lastTime[0] || DEFAULT_LAST_MINUTE) * E_TimeConfig.Minute;
                    const weekDay = TimerUtils.getWeekDay(nowTime);
                    const weekIdx = (weekDay - 1 + 7) % 7;      //js date 0是星期天；配置那边，0是星期1

                    for (let i = 0; i < 7; i++) {
                        if (config.startDay[(7 - i + weekIdx) % 7] === 1) {
                            const startTime = zero - i * E_TimeConfig.Day;
                            const endTime = startTime + last;
                            if (nowTime > endTime) {
                                return startTime;
                            }
                        }
                    }
                }
                break;

            default:
                console.warn('activity 未知的开放时间类型：' + config.timeType);
                break;
        }

        return -1;
    }


    /**
     * 获取特殊时间
     * @param configs 
     */
    private static getSpecialTime(configs: number[]): number {
        const t = TimerUtils.getSpecialTime(
            configs[0] || 0,
            configs[1] || 0,
            configs[2] || 0,
            configs[3] || 0,
            configs[4] || 0,
            configs[5] || 0
        );
        return t;
    }



}
